package top.jfunc.common.propenv;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.jfunc.common.utils.Joiner;

import java.io.InputStream;
import java.util.*;

/**
 * 根据环境变量env加载文件(-DENVSETTING=test)，从类路径下或者给定文件路径寻找，
 * 首先寻找${fileName}-${env}.ext，
 * 没找到就寻找找${env}/${fileName}.ext
 * 没有设置env环境变量的时候，给什么路径就从什么路径找
 * @author 熊诗言
 * @see AbsolutePathEnvStream
 * @see ClasspathEnvStream
 * @see FileEnvStream
 */
public abstract class BaseEnvStream {
    private static final Logger logger = LoggerFactory.getLogger(BaseEnvStream.class);
    private String env = EnvUtil.env();

    private List<EnvFileNameStrategy> strategies = new ArrayList<>(2);

    public BaseEnvStream(){
        //${fileName}-${env}.ext
        strategies.add(new DashStrategy());
        //${env}/${fileName}.ext
        strategies.add(new InsertStrategy());
    }
    /**
     * @param fileName 可以是 jdbc.properties 或者 config/jdbc.properties fileName必须带有扩展名
     *                 根据加载顺序加载到即返回
     * @return InputStream
     */
    public InputStream loadEnvInputStream(String fileName) {
        String env = getEnv();

        List<String> names = getFileNames(fileName, env);

        for (String name : names) {
            logger.debug("env="+env+", try to load " + name);
            InputStream inputStream = loadInputStream(name);
            if(null != inputStream){
                return inputStream;
            }
        }

        String joinedNames = Joiner.on(",").join(names);

        throw new IllegalArgumentException("env="+env+", Properties file not found with: " + joinedNames);
    }

    /**
     * @param fileName 可以是 jdbc.properties 或者 config/jdbc.properties fileName必须带有扩展名
     *                 根据加载顺序把所有的都加载到并返回map
     * @return InputStream
     */
    public Map<String, InputStream> loadEnvInputStreamMap(String fileName) {
        String env = getEnv();

        List<String> names = getFileNames(fileName, env);

        //保证遍历顺序和插入顺序一致
        Map<String, InputStream> map = new LinkedHashMap<>();

        for (String name : names) {
            logger.debug("env="+env+", try to load " + name);
            InputStream inputStream = loadInputStream(name);
            if(null != inputStream){
                map.put(name, inputStream);
            }
        }

        return map;
    }

    protected List<String> getFileNames(String fileName, String env) {
        List<EnvFileNameStrategy> strategies = getStrategies();
        //保证顺序并去重
        Set<String> names = new LinkedHashSet<>(strategies.size()+1);
        for (EnvFileNameStrategy strategy : strategies) {
            String generatedFileName = strategy.generate(fileName, env);
            names.add(generatedFileName);
        }
        //给什么名字原封不动
        names.add(fileName);
        return new ArrayList<>(names);
    }

    /**
     * 子类具体实现获取inputStream的方法
     * @param fileName 文件名
     * @return 没找到就返回null
     */
    protected abstract InputStream loadInputStream(String fileName);

    protected List<EnvFileNameStrategy> getStrategies() {
        return strategies;
    }

    public void setStrategies(List<EnvFileNameStrategy> strategies) {
        this.strategies = strategies;
    }

    public void addEnvFileNameStrategy(EnvFileNameStrategy envFileNameStrategy){
        this.strategies.add(envFileNameStrategy);
    }

    public String getEnv() {
        return env;
    }

    public BaseEnvStream setEnv(String env) {
        this.env = env;
        return this;
    }
}
